Plugins/Community Based Plugins/Microsoft Security Experts/Microsoft Defender Experts Plugin/Dexplugin.yaml (537 lines of code) (raw):

Descriptor: Name: MicrosoftDefenderExpertsPlugin DisplayName: Microsoft Defender Experts Security Copilot Plugin Description: Leverage detections built by the Microsoft Defender Experts team in identifying threat actor activity. For more information on Microsoft Defender Experts, go here https://www.microsoft.com/en-us/security/business/services/microsoft-defender-experts-hunting?msockid=3eb9717c7a346743120665a77b05660a Icon: https://raw.githubusercontent.com/KwachSean/SecurityCopilot/main/DEXlogo_resized_icon.png SkillGroups: - Format: KQL Skills: - Name: DEX-SuspiciousUseOfAzureHound DisplayName: Suspicious Use of AzureHound Description: Detects potential suspicious usage of AzureHound on devices. Inputs: - Name: days Description: Look back x amount of days, for example 10, 20, 30. Required: true Settings: Target: Defender Template: |- DeviceProcessEvents | where TimeGenerated > ago({{days}}d) | where FileName has "azurehound.exe" | where ProcessCommandLine has "azurehound" and ProcessCommandLine has_any ("az-rm", "az-ad", "list", "Invoke-azurehound") - Name: DEX-ReconnaissanceActivityUsingNetworkLogs DisplayName: Reconnaissance Activity Using Network Logs Description: Detects reconnaissance activity leveraging network logs and specific URLs. Inputs: - Name: days Description: Look back x amount of days, for example 10, 20, 30. Required: true Settings: Target: Defender Template: |- DeviceNetworkEvents | where TimeGenerated > ago({{days}}d) | where RemoteUrl in ("login.microsoftonline.com", "graph.microsoft.com") | where InitiatingProcessCommandLine has_any ("list", "-u", "-p", "--u", "--p", "--app", "--secret", "-app", "-secret", "--cert", "-cert", "-j", "--j") | where InitiatingProcessFolderPath !contains "Microsoft" | summarize dcount(RemoteUrl) by bin(Timestamp, 1m), InitiatingProcessFileName, DeviceId | where dcount_RemoteUrl == 2 - Name: DEX-RoadreconAndRoadtxActivity DisplayName: ROADrecon and ROADtx Activity Description: Detects known filenames and command line activity associated with ROADrecon and ROADtx tools. Inputs: - Name: days Description: Look back x amount of days, for example 10, 20, 30. Required: true Settings: Target: Defender Template: |- DeviceProcessEvents | where TimeGenerated > ago({{days}}d) | where InitiatingProcessFileName has_any ("powershell", "cmd.exe", "pwsh.exe") | where FileName has_any ("roadrecon.exe", "roadtx.exe") | where ProcessCommandLine has_any ("auth", "gather", "plugin", "dump", "gettokens", "interactiveauth", "listaliases", "findscope", "device", "prt", "prtauth", "keepassauth", "browserprtauth", "browserprtinject") | project-reorder Timestamp, ReportId, DeviceId, InitiatingProcessCommandLine, FileName, InitiatingProcessFileName, ProcessCommandLine, InitiatingProcessParentFileName, ProcessVersionInfoOriginalFileName, ProcessVersionInfoInternalFileName, InitiatingProcessVersionInfoOriginalFileName, InitiatingProcessFileName - Name: DEX-FederatedIdPAdditionActivity DisplayName: Federated IdP Addition Activity Description: Detects possible roadoidc activity related to federated identity provider addition. Inputs: - Name: days Description: Look back x amount of days, for example 10, 20, 30. Required: true Settings: Target: Defender Template: |- DeviceNetworkEvents | where TimeGenerated > ago({{days}}d) | where InitiatingProcessFileName == "python.exe" | where InitiatingProcessParentFileName == "roadtx.exe" | where InitiatingProcessCommandLine has_any ("federatedappauth", "azurewebsites", "--key-pem", "--cert-pem") | extend RemoteUrl = replace_regex(RemoteUrl, @'http(s)?://', '') | where ActionType == "ConnectionSuccess" | project DeviceId, Timestamp, ReportId, InitiatingProcessFileName, InitiatingProcessId, InitiatingProcessAccountSid, RemoteIP, RemoteUrl, ActionType - Name: DEX-RecentEntraIDJoinedDevices DisplayName: Recent Entra ID-Joined Devices Description: Identifies devices recently joined to Entra ID, potentially by threat actors to maintain access. Inputs: - Name: days Description: Look back x amount of days, for example 10, 20, 30. Required: true Settings: Target: Defender Template: |- AuditLogs | where TimeGenerated > ago({{days}}d) | extend userPrincipalName_ = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName) | extend DeviceRegInfo = tostring(AdditionalDetails[0].value) | extend TrustType = tostring(AdditionalDetails[2].value) | extend DeviceID = tostring(AdditionalDetails[4].value) | where userPrincipalName_ contains " " //add user entity here | project TimeGenerated, OperationName, Category, DeviceRegInfo, DeviceID, TrustType, userPrincipalName_ - Name: DEX-FakeGlobalProtectTool DisplayName: Fake Global Protect Tool Description: Detects possible use of a fake Global Protect tool by looking for known file and folder patterns. Inputs: - Name: days Description: Look back x amount of days, for example 10, 20, 30. Required: true Settings: Target: Defender Template: |- DeviceNetworkEvents | where TimeGenerated > ago({{days}}d) | where InitiatingProcessFileName has_any ("GlobalProtect.exe", "GlobalProtectPortal.exe") | where InitiatingProcessParentFileName endswith ".tmp" | where InitiatingProcessFolderPath has_all ("appdata", "paloalto") - Name: DEX-FakeAuthenticatorExecutable DisplayName: Fake Authenticator Executable Description: Detects use of a fake authenticator executable for information stealing, requiring Microsoft Defender XDR. Inputs: - Name: days Description: Look back x amount of days, for example 10, 20, 30. Required: true Settings: Target: Defender Template: |- DeviceProcessEvents | where TimeGenerated > ago({{days}}d) | where InitiatingProcessFileName has "msedge.exe" | where InitiatingProcessCommandLine has_all ("msedge.exe", "--no-startup-window") | where FileName has "Authenticator.exe" | join kind=inner (DeviceNetworkEvents | where InitiatingProcessFileName has "Authenticator.exe" | where RemoteUrl has "paradiso4.fun" | where ActionType == "ConnectionSuccess") on DeviceId - Name: DEX-EmailBombingActivity DisplayName: Email Bombing Activity Detection Description: Detects possible email bombing activity using anomaly detection on inbound emails. Inputs: - Name: days Description: Look back x amount of days, for example 10, 20, 30. Required: true Settings: Target: Defender Template: |- EmailEvents | where EmailDirection == "Inbound" | where Timestamp > ago({{days}}d) | make-series Emailcount = count() on Timestamp step 1h by RecipientObjectId | extend (Anomalies, AnomalyScore, ExpectedEmails) = series_decompose_anomalies(Emailcount) | mv-expand Emailcount, Anomalies, AnomalyScore, ExpectedEmails to typeof(double), Timestamp | where Anomalies != 0 | where AnomalyScore >= 10 - Name: DEX-TeamsPhishingActivity DisplayName: Teams Phishing Activity Detection Description: Detects possible Teams phishing activity by identifying suspicious chat creations. Inputs: - Name: alertedMachine Description: DeviceId of the alerted machine. Required: true Settings: Target: Defender Template: |- let suspiciousUpns = DeviceProcessEvents | where DeviceId == "{{alertedMachine}}" | where isnotempty(InitiatingProcessAccountUpn) | project InitiatingProcessAccountUpn; CloudAppEvents | where Application == "Microsoft Teams" | where ActionType == "ChatCreated" | where isempty(AccountObjectId) | where RawEventData.ParticipantInfo.HasForeignTenantUsers == true | where RawEventData.CommunicationType == "OneonOne" | where RawEventData.ParticipantInfo.HasGuestUsers == false | where RawEventData.ParticipantInfo.HasOtherGuestUsers == false | where RawEventData.Members[0].DisplayName in ("Microsoft Security", "Help Desk", "Help Desk Team", "Help Desk IT", "Microsoft Security", "office") | where AccountId has "@" | extend TargetUPN = tolower(tostring(RawEventData.Members[1].UPN)) | where TargetUPN in (suspiciousUpns) - Name: DEX-CobaltStrikeDNSBeaconing DisplayName: Cobalt Strike DNS Beaconing Detection Description: Detects suspicious DNS queries associated with Cobalt Strike beacons. Inputs: - Name: days Description: Look back x amount of days, for example 10, 20, 30. Required: true Settings: Target: Defender Template: |- let badNames = dynamic(["aaa.stage.", "post.1"]); (union isfuzzy=true (DnsEvents | where TimeGenerated > ago({{days}}d) | where Name has_any (badNames) | extend Domain = Name, SourceIp = ClientIP, RemoteIP = todynamic(IPAddresses) | mv-expand RemoteIP | extend RemoteIP = tostring(RemoteIP)), (VMConnection | where TimeGenerated > ago({{days}}d) | where isnotempty(RemoteDnsCanonicalNames) | parse RemoteDnsCanonicalNames with * '["' DNSName '"]' * | where DNSName has_any (badNames) | extend Domain = DNSName, RemoteIP = RemoteIp )) | summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by Domain, SourceIp, RemoteIP, Computer | extend timestamp = StartTimeUtc, HostName = split(Computer, '.', 0)[0], DnsDomain = strcat_array(array_slice(split(Computer, '.'), 1, -1), '.') | extend Host_0_HostName = HostName | extend Host_0_DnsDomain = DnsDomain | extend IP_0_Address = RemoteIP - Name: DEX-ExcelLaunchingAnomalousProcesses DisplayName: Excel Launching Anomalous Processes Description: Detects Excel launching anomalous processes congruent with Qakbot payloads, indicating potential malicious activity. Inputs: - Name: days Description: Look back x amount of days, for example 10, 20, 30. Required: true Settings: Target: Defender Template: |- DeviceProcessEvents | where TimeGenerated > ago({{days}}d) | where InitiatingProcessParentFileName has "excel.exe" or InitiatingProcessFileName =~ "excel.exe" | where InitiatingProcessFileName in~ ("excel.exe", "regsvr32.exe") | where FileName in~ ("regsvr32.exe", "rundll32.exe") | where ProcessCommandLine has @"..\" - Name: DEX-GeneralAttemptsToAccessLocalEmailStore DisplayName: General Attempts to Access Local Email Store Description: Detects attempts to access files in the local path containing Outlook emails. Inputs: - Name: days Description: Look back x amount of days, for example 10, 20, 30. Required: true Settings: Target: Defender Template: |- DeviceFileEvents | where TimeGenerated > ago({{days}}d) | where FolderPath hasprefix "EmailStorage" | where FolderPath has "Outlook" | project FileName, FolderPath, InitiatingProcessFileName, InitiatingProcessCommandLine, DeviceId, Timestamp - Name: DEX-QakbotCraigslistDomains DisplayName: Qakbot Craigslist Domains Detection Description: Detects malicious domains impersonating Craigslist used by Qakbot operators. Inputs: - Name: days Description: Look back x amount of days, for example 10, 20, 30. Required: true Settings: Target: Defender Template: |- DeviceNetworkEvents | where TimeGenerated > ago({{days}}d) | where RemoteUrl matches regex @"abuse\.[a-zA-Z]\d{2}-craigslist\.org" - Name: DEX-QakbotEmailTheft DisplayName: Qakbot Email Theft Detection Description: Detects email stealing activities by Qakbot using specific patterns. Inputs: - Name: days Description: Look back x amount of days, for example 10, 20, 30. Required: true Settings: Target: Defender Template: |- DeviceFileEvents | where TimeGenerated > ago({{days}}d) | where InitiatingProcessFileName =~ 'ping.exe' and InitiatingProcessCommandLine == 'ping.exe -t 127.0.0.1' and InitiatingProcessParentFileName in~('msra.exe', 'mobsync.exe') and FolderPath endswith ".eml" - Name: DEX-QakbotReconnaissanceActivities DisplayName: Qakbot Reconnaissance Activities Detection Description: Detects reconnaissance and beaconing activities after code injection by Qakbot. Inputs: - Name: days Description: Look back x amount of days, for example 7, 14, 21. Required: true Settings: Target: Defender Template: |- DeviceProcessEvents | where TimeGenerated > ago({{days}}d) | where InitiatingProcessFileName == InitiatingProcessCommandLine | where ProcessCommandLine has_any ( "whoami /all","cmd /c set","arp -a","ipconfig /all","net view /all","nslookup -querytype=ALL -timeout=10", "net share","route print","netstat -nao","net localgroup") | summarize dcount(FileName), make_set(ProcessCommandLine) by DeviceId, bin(Timestamp, 1d), InitiatingProcessFileName, InitiatingProcessCommandLine | where dcount_FileName >= 8 - Name: DEX-SuspiciousNamedPipes DisplayName: Suspicious Named Pipes Detection Description: Detects named pipe events that may be linked to Cobalt Strike usage. Inputs: - Name: hours Description: Look back x amount of hours, for example 1, 2, 3. Required: true Settings: Target: Defender Template: |- let timeframe = {{hours}}h; let CobaltStrikeDefaults = dynamic([@"msagent_", @"MSSE-", @"postex_", @"status_", @"mypipe-f", @"mypipe-h", @"ntsvcs_", @"scerpc_", @"mojo.5688.8052."]); let CobaltStrikeMallable = dynamic([@"win_svc", @"ntsvcs", @"scerpc", @"status_", @"SearchTextHarvester", @"DserNamePipe", @"wkssvc_", @"scerpc_", @"spoolss_", @"CatalogChangeListener", @"fullduplex_", @"demoagent_", @"PGMessagePipe", @"MsFteWds", @"postex_ssh_", @"windows.update.manager", @"\f4c3", @"\f53f", @"halfduplex_"]); DeviceEvents | where Timestamp >= ago(timeframe) | where ActionType == "NamedPipeEvent" | extend AdditionalFields = parse_json(AdditionalFields) | extend ThreadId = tostring(AdditionalFields.ThreadId) | extend PipeName = tostring(AdditionalFields.PipeName) | extend InitiatingPID = tostring(InitiatingProcessId) | extend InitiatingParentPID = tostring(InitiatingProcessParentId) | where PipeName has_any (CobaltStrikeDefaults) or (PipeName matches regex @"\\mojo\.\d+\.\d+\." and not(PipeName matches regex @"\\mojo\.\d+\.\d+\.\d+$" or PipeName has InitiatingPID or PipeName has InitiatingParentPID or PipeName has ThreadId)) or (PipeName matches regex @"\\(edge|chrome)\.sync\.\d+\.\d+\." and not(PipeName matches regex @"\\(edge|chrome|edge\.sync|chrome\.sync)\.\d+\.\d+\.\d+$" or PipeName has InitiatingPID or PipeName has InitiatingParentPID or PipeName has ThreadId)) or (PipeName matches regex @"\\PSHost\.\d+\." and not(PipeName matches regex @"\\PSHost\.\d+\.\d+\." or PipeName has InitiatingPID or PipeName has InitiatingParentPID)) or (PipeName matches regex @"\\crashpad_" and not(PipeName matches regex @"\\crashpad_\d+_[A-Z]+" or PipeName has InitiatingPID or PipeName has InitiatingParentPID)) or (PipeName matches regex @"\\cubeb-pipe-" and not(PipeName matches regex @"\\cubeb-pipe-\d+_[0-9]{1,3}+" or PipeName has InitiatingPID)) or (PipeName has_any (CobaltStrikeMallable) and PipeName matches regex @"[a-fA-F0-9]{2,10}$") or (PipeName matches regex @"\\pipe\\[0-9a-f]{7,10}" or PipeName matches regex @"\\pipe\\[0-9a-f]{8}") - Name: DEX-CobaltStrikeInvokedWithWMI DisplayName: Cobalt Strike Invoked with WMI Detection Description: Detects possible invocation of Cobalt Strike using Windows Management Instrumentation (WMI). Inputs: - Name: days Description: Look back x amount of days, for example 7, 14, 21. Required: true Settings: Target: Defender Template: |- DeviceProcessEvents | where TimeGenerated > ago({{days}}d) | where InitiatingProcessFileName =~ 'wmiprvse.exe' | where FileName =~ 'powershell.exe' and (ProcessCommandLine hasprefix '-e' or ProcessCommandLine contains 'frombase64') | where ProcessCommandLine matches regex '[A-Za-z0-9+/]{50,}[=]{0,2}' | where ProcessCommandLine !has 'Windows\\CCM\\' | project DeviceId, Timestamp, InitiatingProcessId, InitiatingProcessFileName, ProcessId, FileName, ProcessCommandLine - Name: DEX-AutomatedEmailNotificationsAndSuspiciousSignInActivity DisplayName: Automated Email Notifications and Suspicious Sign-In Activity Detection Description: Correlates automated email notifications with suspicious sign-in activity to identify potential compromises. Inputs: - Name: days Description: Look back x amount of days, for example 1, 2, 3. Required: true Settings: Target: Defender Template: |- let usersWithSuspiciousEmails = EmailEvents | where TimeGenerated > ago({{days}}d) | where SenderFromAddress in ("no-reply@notify.microsoft.com", "no-reply@dropbox.com") or InternetMessageId startswith "<OneTimePasscode" | where isnotempty(RecipientObjectId) | distinct RecipientObjectId; AADSignInEventsBeta | where TimeGenerated > ago({{days}}d) | where AccountObjectId in (usersWithSuspiciousEmails) | where RiskLevelDuringSignIn == 100 - Name: DEX-FileShareContentsAndSuspiciousSignInActivity DisplayName: File Share Contents and Suspicious Sign-In Activity Detection Description: Correlates file share emails with suspicious sign-ins to detect potential compromises. Inputs: - Name: days Description: Look back x amount of days, for example 1, 2, 3. Required: true Settings: Target: Defender Template: |- let usersWithSuspiciousEmails = EmailEvents | where TimeGenerated > ago({{days}}d) | where Subject has_all ("shared", "with you") | where Subject has_any ("payment", "invoice", "urgent", "mandatory", "Payoff", "Wire", "Confirmation", "password") | where isnotempty(RecipientObjectId) | summarize RecipientCount = dcount(RecipientObjectId), RecipientList = make_set(RecipientObjectId) by Subject | where RecipientCount >= 10 | mv-expand RecipientList to typeof(string) | distinct RecipientList; AADSignInEventsBeta | where TimeGenerated > ago({{days}}d) | where AccountObjectId in (usersWithSuspiciousEmails) | where RiskLevelDuringSignIn == 100 - Name: DEX-OneDriveOrSharePointMassFileSharingDetection DisplayName: OneDrive or SharePoint Mass File Sharing Detection Description: Detects files shared with multiple participants in OneDrive or SharePoint, indicating potential lateral movements or BEC attacks. Inputs: - Name: days Description: Look back x amount of days, for example 1, 2, 3. Required: true Settings: Target: Defender Template: |- let securelinkCreated = CloudAppEvents | where TimeGenerated > ago({{days}}d) | where ActionType == "SecureLinkCreated" | project FileCreatedTime = Timestamp, AccountObjectId, ObjectName; let filesCreated = securelinkCreated | where isnotempty(ObjectName) | distinct tostring(ObjectName); CloudAppEvents | where TimeGenerated > ago({{days}}d) | where ActionType == "AddedToSecureLink" | where Application in ("Microsoft SharePoint Online", "Microsoft OneDrive for Business") | extend FileShared = tostring(RawEventData.ObjectId) | where FileShared in (filesCreated) | extend UserSharedWith = tostring(RawEventData.TargetUserOrGroupName) | extend TypeofUserSharedWith = RawEventData.TargetUserOrGroupType | where TypeofUserSharedWith == "Guest" | where isnotempty(FileShared) and isnotempty(UserSharedWith) | join kind=inner securelinkCreated on $left.FileShared == $right.ObjectName | summarize NumofUsersSharedWith = dcount(UserSharedWith) by FileShared | where NumofUsersSharedWith >= 20 - Name: DEX-DropboxMassFileSharingDetection DisplayName: Dropbox Mass File Sharing Detection Description: Detects files hosted on Dropbox that have been shared with multiple participants. Inputs: - Name: days Description: Look back x amount of days, for example 1, 2, 3. Required: true Settings: Target: Defender Template: |- CloudAppEvents | where TimeGenerated > ago({{days}}d) | where ActionType in ("Added users and/or groups to shared file/folder", "Invited user to Dropbox and added them to shared file/folder") | where Application == "Dropbox" | where ObjectType == "File" | extend FileShared = tostring(ObjectName) | where isnotempty(FileShared) | mv-expand ActivityObjects | where ActivityObjects.Type == "Account" and ActivityObjects.Role == "To" | extend SharedBy = AccountId | extend UserSharedWith = tostring(ActivityObjects.Name) | summarize dcount(UserSharedWith) by FileShared, AccountObjectId | where dcount_UserSharedWith >= 20 - Name: DEX-PossibleAiTMPhishingAttemptAgainstEntraID DisplayName: Possible AiTM Phishing Attempt Against Entra ID Description: | Threat actors may attempt to phish users to hijack sign-in sessions, even if MFA is enabled, by stealing and replaying credentials and session cookies. This detection looks for successful Entra ID sign-ins with a high-risk profile and then checks for network connections to the same IP address immediately before the sign-in, indicating possible phishing activity. Inputs: - Name: days Description: Look back x amount of days, for example 1, 2, 3. Required: true Settings: Target: Defender Template: |- let time_threshold = 10m; let RiskySignins = materialize (SigninLogs | where TimeGenerated > ago({{days}}d) | where ResultType == 0 | where RiskLevelDuringSignIn =~ "high" or RiskLevelAggregated =~ "high" | extend SignInTime = TimeGenerated, Name = split(UserPrincipalName, "@")[0], UPNSuffix = split(UserPrincipalName, "@")[1]); let ips = todynamic(toscalar(RiskySignins | summarize make_list(IPAddress))); RiskySignins | join kind=inner (_Im_WebSession(starttime=ago({{days}}d), ipaddr_has_any_prefix=ips, eventresult="Success", pack=True)) on $left.IPAddress == $right.DstIpAddr | where EventStartTime < TimeGenerated | extend TimeDelta = TimeGenerated - EventStartTime | where TimeDelta <= time_threshold | extend NetworkEventStartTime = EventStartTime, NetworkEventEndTime = EventEndTime | extend SrcUsername = column_ifexists("SrcUsername", "Unknown") | project-reorder SignInTime, UserPrincipalName, IPAddress, AppDisplayName, ClientAppUsed, DeviceDetail, LocationDetails, NetworkLocationDetails, RiskEventTypes, UserAgent, NetworkEventStartTime, NetworkEventEndTime, SrcIpAddr, DstIpAddr, DstPortNumber, Dvc, DvcHostname, SrcBytes, NetworkProtocol, SrcUsername - Name: DEX-SigninsFromVPSProviders DisplayName: Sign-ins From VPS Providers Description: Detects successful logons from known VPS providers with suspicious token patterns. Inputs: - Name: riskScoreCutoff Description: Adjust this based on the volume of results; default is 20. Required: false DefaultValue: 20 Settings: Target: Defender Template: |- let riskScoreCutoff = {{riskScoreCutoff}}; let IP_Data = (externaldata(network:string) [@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/VPS_Networks.csv"] with (format="csv")); SigninLogs | where ResultType == 0 | extend additionalDetails = tostring(Status.additionalDetails) | evaluate ipv4_lookup(IP_Data, IPAddress, network, return_unmatched = false) | summarize make_set(additionalDetails), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by IPAddress, UserPrincipalName | extend timestamp = StartTime, UserPrincipalName = tolower(UserPrincipalName), AccountCustomEntity = UserPrincipalName, IPCustomEntity = IPAddress | join kind=leftouter ( IdentityInfo | summarize LatestReportTime = arg_max(TimeGenerated, *) by AccountUPN | extend UserPrincipalName = tolower(AccountUPN) ) on UserPrincipalName | join kind=leftouter ( BehaviorAnalytics | where ActivityType in ("FailedLogOn", "LogOn") | where isnotempty(SourceIPAddress) | where ActivityInsights["ISPUncommonlyUsedInTenant"] == True | summarize IPInvestigationPriority = sum(InvestigationPriority) by IPAddress = SourceIPAddress ) on IPAddress | extend UEBARiskScore = IPInvestigationPriority | where UEBARiskScore > riskScoreCutoff | sort by UEBARiskScore desc - Name: DEX-SigninsFromNordVPNProviders DisplayName: Sign-ins from Nord VPN Providers Description: Tracks sign-ins via Nord VPN using a daily-updated API to detect unusual activity. Inputs: - Name: hours Description: Look back x amount of hours, for example 4, 8, 12. Required: true Settings: Target: Defender Template: |- let nord_vpn_feed = (externaldata(id:int, ip_address:string, search_keywords:dynamic, categories:dynamic, name:string, domain:string, price:int, flag:string, country:string, location:dynamic, load:int, features:dynamic) [@"https://raw.githubusercontent.com/microsoft/mstic/master/nordvpn-servers.csv"] with (format="csv", ignoreFirstRecord=True)); SigninLogs | where TimeGenerated > ago({{hours}}h) | where ResultType == 0 | summarize TotalEvents = count(), AppList = make_set(AppDisplayName), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by IPAddress, UserPrincipalName, ClientAppUsed, ConditionalAccessStatus, AuthenticationRequirement, RiskDetail | join kind=inner nord_vpn_feed on $left.IPAddress == $right.ip_address | extend timestamp = StartTime, UserPrincipalName = tolower(UserPrincipalName), AccountCustomEntity = UserPrincipalName, IPCustomEntity = IPAddress | join kind=leftouter ( IdentityInfo | summarize LatestReportTime = arg_max(TimeGenerated, *) by AccountUPN | extend UserPrincipalName = tolower(AccountUPN) ) on UserPrincipalName | join kind=leftouter ( BehaviorAnalytics | where ActivityType in ("FailedLogOn", "LogOn") | where isnotempty(SourceIPAddress) | where ActivityInsights["ISPUncommonlyUsedInTenant"] == True | summarize IPInvestigationPriority = sum(InvestigationPriority) by IPAddress = SourceIPAddress ) on IPAddress | extend UEBARiskScore = IPInvestigationPriority | sort by UEBARiskScore desc - Name: DEX-SuccessfulSigninFromNonCompliantDevice DisplayName: Successful Sign-in From Non-Compliant Device Description: Detects successful sign-ins from devices marked non-compliant. Inputs: - Name: riskScoreCutoff Description: Adjust this based on the volume of results; default is 0. Required: false DefaultValue: 0 Settings: Target: Defender Template: |- SigninLogs | where ResultType == 0 | where tostring(DeviceDetail.isCompliant) == "false" | extend Account_0_Name = tolower(UserPrincipalName) | extend IP_0_Address = IPAddress | join kind=leftouter ( IdentityInfo | summarize LatestReportTime = arg_max(TimeGenerated, *) by AccountUPN | extend Account_0_Name = tolower(AccountUPN) ) on Account_0_Name | join kind=leftouter ( BehaviorAnalytics | where ActivityType in ("FailedLogOn", "LogOn") | where isnotempty(SourceIPAddress) | summarize IPInvestigationPriority = sum(InvestigationPriority) by IP_0_Address = SourceIPAddress ) on IP_0_Address | extend UEBARiskScore = IPInvestigationPriority | where UEBARiskScore > {{riskScoreCutoff}} | sort by UEBARiskScore desc